package main

import (
	"go.etcd.io/etcd/clientv3"
	"time"
	"fmt"
	"context"
	"strconv"
	"go.etcd.io/etcd/mvcc/mvccpb"
)

func TestCURD(client *clientv3.Client){
	kv := clientv3.NewKV(client)

	// 添加记录
	resp, err := kv.Put(context.TODO(), "/TestCURD/key", "value_string", clientv3.WithPrevKV())
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(resp.Header.Revision)
	if resp.PrevKv != nil {
		fmt.Println(string(resp.PrevKv.Value))
	}

	// 获取记录
	getRsp, err := kv.Get(context.TODO(), "/TestCURD/key")
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println(getRsp.Header.Revision)
	fmt.Println(getRsp.Kvs)

	//删除记录
	delRsp, err := kv.Delete(context.TODO(), "/TestCURD/key", clientv3.WithPrevKV())
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(delRsp.Header.Revision)
	if len(delRsp.PrevKvs) != 0 {
		fmt.Println(delRsp.PrevKvs)
	}
}

func TestPrefixGet(client *clientv3.Client) {
	kv := clientv3.NewKV(client)

	// 批量添加记录
	for i := 0; i < 5; i++  {
		_, err := kv.Put(context.TODO(),
			"/TestCURD/key" + strconv.Itoa(i+1), "value_string" + strconv.Itoa(i+1))
		if err != nil {
			fmt.Println(err)
			return
		}
	}

	// 获取记录
	getRsp, err := kv.Get(context.TODO(), "/TestCURD/key", clientv3.WithPrefix())
	if err != nil {
		fmt.Println(err)
		return
	}

	for _, kvpair := range getRsp.Kvs  {
		fmt.Println(string(kvpair.Key), string(kvpair.Value))
	}

	return
}

func TestLease(client *clientv3.Client)  {
	kv := clientv3.NewKV(client)

	// 申请一个租约
	lease := clientv3.NewLease(client)

	// 设定一个10秒的租约
	leaseRsp, err := lease.Grant(context.TODO(), 3)
	if err != nil {
		fmt.Println(err)
		return
	}

	// 添加记录
	resp, err := kv.Put(context.TODO(),
		"/lock/lock1", "", clientv3.WithLease(leaseRsp.ID))
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("write lock succ", resp.Header.Revision)

	for{
		getResp, err := kv.Get(context.TODO(), "/lock/lock1")
		if err != nil {
			fmt.Println(err)
			return
		}
		if getResp.Count == 0 {
			fmt.Println("time out unlock")
			break
		}
		fmt.Println("in lock", getResp.Kvs)
		time.Sleep(1 * time.Second)
	}
}

func TestWatch(client *clientv3.Client)  {
	kv := clientv3.NewKV(client)

	KeyStr := "/watch/w1"

	// 添加记录
	_, err := kv.Put(context.TODO(), KeyStr, "test")
	if err != nil {
		fmt.Println(err)
		return
	}

	// 读取记录，计算开始观察版本号
	getResp, err := kv.Get(context.TODO(), KeyStr)
	if err != nil {
		fmt.Println(err)
		return
	}

	watchStartRev := getResp.Header.Revision + 1

	// 启动一个协程序不断修改数据
	go func() {
		for {
			time.Sleep(1 * time.Second)
			kv.Put(context.TODO(), KeyStr, "test2")
			kv.Delete(context.TODO(), KeyStr)
		}
	}()

	// 创建一个监听者
	watcher := clientv3.NewWatcher(client)
	watchRespChan := watcher.Watch(context.TODO(), KeyStr, clientv3.WithRev(watchStartRev))

	for resp := range watchRespChan {
		for _, event := range resp.Events  {
			switch event.Type {
			case mvccpb.PUT:
				fmt.Println("modify ", string(event.Kv.Value))
			case mvccpb.DELETE:
				fmt.Println("delete ", string(event.Kv.Key))
			}
		}
	}
}

func main() {
	config := clientv3.Config{
		Endpoints:[]string{"9.134.0.183:2379"},
		DialTimeout:5 * time.Second,
	}

	client, err := clientv3.New(config)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer client.Close()

	//测试增、删、改、查
	//TestCURD(client)

	// 批量查找
	//TestPrefixGet(client)

	// 测试租约功能
	//TestLease(client)

	// 测试watch功能
	TestWatch(client)
}
